<template>
    <transition name="el-zoom-in-center">
        <div
            class="el-popper is-pure is-light el-dropdown__popper ba-contextmenu"
            :style="menuStyle"
            :key="Math.random()"
            v-show="state.show"
            aria-hidden="false"
            data-popper-placement="bottom"
            ref="menuRef"
        >
            <ul class="el-dropdown-menu">
                <template v-for="(item, idx) in props.items" :key="idx">
                    <li class="el-dropdown-menu__item" :class="item.disabled ? 'is-disabled' : ''" tabindex="-1" @click="onContextmenuItem(item)">
                        <Icon size="12" :name="item.icon" />
                        <span>{{ item.label }}</span>
                    </li>
                </template>
            </ul>
            <span class="el-popper__arrow" :style="{ left: `${state.arrowAxis}px` }"></span>
        </div>
    </transition>
</template>

<script setup lang="ts">
import { onMounted, reactive, toRaw, ref, computed, nextTick } from 'vue'
import type { Axis, ContextmenuItemClickEmitArg, Props } from './interface'
import type { RouteLocationNormalized } from 'vue-router'
import { useEventListener } from '@vueuse/core'

const props = withDefaults(defineProps<Props>(), {
    width: 150,
    items: () => [],
})

const emits = defineEmits<{
    (e: 'contextmenuItemClick', item: ContextmenuItemClickEmitArg): void
}>()

// 菜单元素引用
const menuRef = ref<HTMLDivElement | null>(null)

const state: {
    show: boolean
    axis: {
        x: number
        y: number
    }
    menu: RouteLocationNormalized | undefined
    arrowAxis: number
    menuHeight: number
    menuWidth: number
} = reactive({
    show: false,
    axis: {
        x: 0,
        y: 0,
    },
    menu: undefined,
    arrowAxis: 10,
    menuHeight: 0,  // 菜单高度
    menuWidth: 0    // 菜单宽度
})

// 计算菜单样式，包括位置和宽度
const menuStyle = computed(() => {
    // 获取视口尺寸
    const viewportWidth = window.innerWidth || document.documentElement.clientWidth
    const viewportHeight = window.innerHeight || document.documentElement.clientHeight
    
    // 默认坐标
    let x = state.axis.x
    let y = state.axis.y
    
    // 考虑边界情况
    if (state.menuWidth > 0) {
        // 如果菜单会超出右侧边界，则向左偏移
        if (x + state.menuWidth > viewportWidth - 10) {
            x = viewportWidth - state.menuWidth - 10
        }
    }
    
    if (state.menuHeight > 0) {
        // 如果菜单会超出底部边界，则向上偏移
        if (y + state.menuHeight > viewportHeight - 10) {
            y = viewportHeight - state.menuHeight - 10
        }
    }
    
    // 返回计算后的样式
    return {
        top: `${y}px`,
        left: `${x}px`,
        width: `${props.width}px`
    }
})

const onShowContextmenu = (menu: RouteLocationNormalized, axis: Axis) => {
    state.menu = menu
    state.axis = axis
    state.show = true
    
    // 在下一个渲染周期计算菜单尺寸
    nextTick(() => {
        if (menuRef.value) {
            state.menuHeight = menuRef.value.offsetHeight
            state.menuWidth = menuRef.value.offsetWidth
        }
    })
}

const onContextmenuItem = (item: ContextmenuItemClickEmitArg) => {
    if (item.disabled) return
    item.menu = toRaw(state.menu)
    emits('contextmenuItemClick', item)
    onHideContextmenu()  // 点击菜单项后自动隐藏菜单
}

const onHideContextmenu = () => {
    state.show = false
}

defineExpose({
    onShowContextmenu,
    onHideContextmenu,
})

onMounted(() => {
    useEventListener(document, 'click', onHideContextmenu)
    useEventListener(window, 'scroll', onHideContextmenu)  // 滚动页面时隐藏菜单
    useEventListener(window, 'resize', onHideContextmenu)  // 调整窗口大小时隐藏菜单
})
</script>

<style scoped lang="scss">
.ba-contextmenu {
    position: fixed;  /* 使用fixed定位，确保菜单不受滚动影响 */
    z-index: 9999;
}
.el-popper,
.el-popper.is-light .el-popper__arrow::before {
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    border: none;
}
.el-dropdown-menu__item {
    padding: 8px 20px;
    user-select: none;
}
.el-dropdown-menu__item .icon {
    margin-right: 5px;
}
.el-dropdown-menu__item:not(.is-disabled) {
    &:hover {
        background-color: var(--el-dropdown-menuItem-hover-fill);
        color: var(--el-dropdown-menuItem-hover-color);
        .fa {
            color: var(--el-dropdown-menuItem-hover-color) !important;
        }
    }
}
</style>
